home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / bipl.zip / PROGS.ZIP / PT.ICN < prev    next >
Text File  |  1992-09-28  |  37KB  |  1,028 lines

  1. ############################################################################
  2. #
  3. #    File:     pt.icn
  4. #
  5. #    Subject:  Program to produce parse table generator
  6. #
  7. #    Author:   Deeporn H. Beardsley
  8. #
  9. #    Date:     December 10, 1988
  10. #
  11. ###########################################################################
  12. #
  13. #  See pt.man for a description of functionality as well as input and
  14. #  output format.
  15. #
  16. ############################################################################
  17.  
  18. #**********************************************************************
  19. #*                                                                    *
  20. #* Main procedure as well as                                          * 
  21. #*      a routine to generate production table, nonterminal, terminal *
  22. #*      and epsilon sets from the input grammar                       *
  23. #**********************************************************************
  24. #
  25. #  1.  Data structures:-
  26. #
  27. #       E.g.  Grammar:-
  28. #               
  29. #               A -> ( B )
  30. #               A -> B , C
  31. #               A -> a
  32. #               B -> ( C )
  33. #               B -> C , A
  34. #               B -> b
  35. #               C -> ( A )
  36. #               C -> A , B
  37. #               C -> c
  38. #
  39. #       prod_table                   prod
  40. #               __________________         _____  _____  _____  
  41. #               |     |          |     num | 1 |  | 2 |  | 3 |
  42. #               | "A" |    ------|-->[     |---| ,|---| ,|---| ]
  43. #               |     |          |     rhs |_|_|  |_|_|  |_|_|
  44. #               |     |          |           |      |      v  
  45. #               |     |          |           |      v      ["a"]
  46. #               |     |          |           v      ["B",",","C"]
  47. #               |     |          |           ["(","B",")"]
  48. #               |_____|__________|         _____  _____  _____  
  49. #               |     |          |     num | 4 |  | 5 |  | 6 |
  50. #               | "B" |    ------|-->[     |---| ,|---| ,|---| ]
  51. #               |     |          |     rhs |_|_|  |_|_|  |_|_|
  52. #               |     |          |           |      |      v  
  53. #               |     |          |           |      v      ["b"]
  54. #               |     |          |           v      ["C",",","A"]
  55. #               |     |          |           ["(","C",")"]
  56. #               |_____|__________|         _____  _____  _____  
  57. #               |     |          |     num | 7 |  | 8 |  | 9 |
  58. #               | "C" |    ------|-->[     |---| ,|---| ,|---| ]
  59. #               |     |          |     rhs |_|_|  |_|_|  |_|_|
  60. #               |     |          |           |      |      v  
  61. #               |     |          |           |      v      ["c"]
  62. #               |     |          |           v      ["A",",","B"]
  63. #               |     |          |           ["(","A",")"]
  64. #               ------------------
  65. #
  66. #               __________________
  67. #       firsts  | "A" |    ------|-->("(", "a", "b", "c")
  68. #               |-----|----------|
  69. #               | "B" |    ------|-->("(", "a", "b", "c")
  70. #               |-----|----------|
  71. #               | "C" |    ------|-->("(", "a", "b", "c")
  72. #               ------------------
  73. #
  74. #               _______
  75. #       NTs     |  ---|-->("A", "B", "C")
  76. #               -------
  77. #
  78. #               _______
  79. #       Ts      |  ---|-->("(", "a", "b", "c")
  80. #               -------
  81. #
  82. #  2.  Algorithm:-
  83. #
  84. #       get_productions() -- build productions table (& NT, T 
  85. #                       and epsilon sets):-
  86. #               open grammar file or from stdin
  87. #               while can get an input line, i.e. production, do
  88. #                 get LHS token and use it as entry value to table
  89. #                   (very first LHS token is start symbol of grammar)
  90. #                   (enter token in nonterminal, NT, set)
  91. #                 get each RHS token & form a list, put this list 
  92. #                   in the list, i.e.assigned value, of the table
  93. #                   (enter each RHS token in terminal, T, set)
  94. #                   (if first RHS token is epsilon
  95. #                      enter LHS token in the epsilon set)
  96. #               (T is the difference of T and NT)
  97. #               close grammar file
  98. #
  99. #**********************************************************************
  100. global prod_table, NTs, Ts, firsts, stateL, itemL
  101. global StartSymbol, start, eoi, epsilon
  102. global erratta            # to list all items in a state (debugging)
  103. record prod(num, rhs)           # assigned values for prod_table
  104. record arc(From, To)            # firsts computation -- closure
  105. record item(prodN, lhs, rhs1, rhs2, NextI)
  106. record state(C_Set, I_Set, goto)
  107. procedure main(opt_list)
  108.   local opt
  109.  
  110.   start := "START"              # start symbol for augmented grammar
  111.   eoi := "EOI"                  # end-of-input token (constant)
  112.   epsilon := "EPSILON"          # epsilon token (constant)
  113.   prod_table := table()         # productions
  114.   NTs := set()                  # non-terminals
  115.   Ts := set()                   # terminals
  116.   firsts := table()             # nonterminals only; first(T) = {T}
  117.   get_firsts(get_productions())
  118.   if /StartSymbol then exit(0)    # input file empty
  119.   write_prods()
  120.   if opt := (!opt_list == "-nt") then
  121.     write_NTs()
  122.   if opt := (!opt_list == "-t") then
  123.     write_Ts()
  124.   if opt := (!opt_list == "-f") then
  125.     write_firsts()
  126.   if opt := (!opt_list == "-e") then
  127.     erratta := 1  
  128.   else
  129.     erratta := 0  
  130.   stateL := list()              # not popped, only for referencing
  131.   itemL := list()               # not popped, only for referencing
  132.   state0()                      # closure of start production
  133.   gotos()                       # sets if items
  134.   p_table()                     # output parse table
  135. end
  136.  
  137. procedure get_productions()
  138.   local Epsilon_Set, LHS, first_RHS_token, grammarFile, line, prods, temp_list
  139.   local token, ws
  140.  
  141.   prods := 0                    # for enumeration of productions
  142.   ws := ' \t'
  143.   Epsilon_Set := set()          # NT's that have epsilon production
  144.   grammarFile := (open("grammar") | &input)
  145.   while line := read(grammarFile) do {
  146.     first_RHS_token := &null    # to detect epsilon production
  147.     temp_list := []             # RHS of production--list of tokens
  148.     line ? {
  149.       tab(many(ws))
  150.       LHS := tab(upto(ws))      # LHS of production--nonterminal
  151.       /firsts[LHS] := set()     
  152.       /StartSymbol := LHS       # start symbol for unaug. grammar
  153.       insert(NTs, LHS)          # collect nonterminals
  154.       tab(many(ws)); tab(match("->")); tab(many(ws))
  155.       while put(temp_list, token := tab(upto(ws))) do {
  156.         /first_RHS_token := token
  157.         insert(Ts, token)       # put all RHS tokens into T set for now
  158.         tab(many(ws))
  159.       }
  160.       token := tab(0)        # get last RHS non-ws token
  161.       if *token > 0 then {
  162.         put(temp_list, token)
  163.         /first_RHS_token := token
  164.         insert(Ts, token)
  165.       }
  166.       Ts --:= NTs               # set of terminals
  167.       delete(Ts, epsilon)    # EPSILON is not a terminal
  168.       /prod_table[LHS] := []
  169.       put(prod_table[LHS], prod(prods +:=1, temp_list))
  170.     }
  171.     if first_RHS_token == epsilon then
  172.       insert(Epsilon_Set, LHS)
  173.   }
  174.   if not (grammarFile === &input) then 
  175.     close(grammarFile)
  176.   return Epsilon_Set
  177. end
  178. #**********************************************************************
  179. #*                                                                    *
  180. #* Routines to generate first sets                                    *
  181. #**********************************************************************
  182. #  1.  Data structures:-
  183. #       (see also data structures in mainProds.icn)
  184. #
  185. #               __________________
  186. #       needs   | "A" |    ------|-->[B]
  187. #               |-----|----------|
  188. #               | "B" |    ------|-->[C]
  189. #               |-----|----------|
  190. #               | "C" |    ------|-->[A]
  191. #               ------------------
  192. #
  193. #       has_all_1st
  194. #               _______
  195. #               |  ---|-->("A", "C")
  196. #               -------
  197. #
  198. #
  199. #       G    |-----------------------| 
  200. #            |  __________________   v 
  201. #            |  | "A" |    ------|-->(B)<--------|
  202. #            |  |-----|----------|               |
  203. #            |--|---  |      ----|-->"A"         |
  204. #               |-----|----------|               |
  205. #               | "B" |    ------|-->(C)<-----|  |
  206. #               |-----|----------|            |  |
  207. #               | (C) |    ------|-->"B"      |  |
  208. #               |-----|----------|            |  |
  209. #               | "C" |    ------|-->(A)<--|  |  |
  210. #               |-----|----------|         |  |  |
  211. #               | (A) |    ------|-->"C"   |  |  |
  212. #               ------------------         |  |  |
  213. #                                          |  |  |
  214. #       closure_table                      |  |  |
  215. #               __________________         |  |  |
  216. #               | "A" |    ------|-->( ----| ,| ,| ) 
  217. #               |-----|----------|
  218. #               | "B" |    ------|-->( as above    )
  219. #               |-----|----------|
  220. #               | "C" |    ------|-->( as above    )
  221. #               ------------------
  222. #
  223. #       (Note: G table: the entry values (B) and (C) should be analogous
  224. #                       to that of '(A)'.)
  225. #
  226. #  2.  Algorithms:-
  227. #
  228. #       2.1  Firsts sets (note: A is nonterminal & 
  229. #                               beta is a string of symbols):-
  230. #                         For definition, see Aho, et al, Compilers...
  231. #                               Addison-Wesley, 1986, p.188)
  232. #               for each production A -> beta (use production table above)
  233. #                 loop1
  234. #                   case next RHS token, B, is
  235. #                     epsilon    :  do nothing, break from loop1
  236. #                     terminal   :  insert it in first(A), break from loop1
  237. #                     nonterminal:  put B in needs[A] table
  238. #                                   if B in epsilon set & last RHS token
  239. #                                     insert A in epsilon set
  240. #                                     break from loop1
  241. #                                   loop1
  242. #               collect has_all_1st set (NTs whose first is fully defined
  243. #                       i.e. NTs not entry value of needs table)
  244. #               Loop2 (fill_firsts)
  245. #                 for each NT B in each needs[A]
  246. #                   if B is in has_all_1st
  247. #                     insert all elements of first(B) in first(A)
  248. #                     delete B from needs[A]
  249. #                 if needs[A] is empty 
  250. #                   insert A in has_all_1st
  251. #                 if *has_all_1st set equal to *NTs set
  252. #                   exit loop2
  253. #                 if *has_all_1st set not equal to *NTs set
  254. #                   if *has_all_1st not changed from beginning of loop2
  255. #                   (i.e. circular dependency e.g.
  256. #                       needs[X] = [Y]
  257. #                       needs[Y] = [Z]
  258. #                       needs[Z] = [X])
  259. #                       find closure of each A
  260. #                       find a set of A's whose closure sets are same
  261. #                         pool their firsts together
  262. #                         add pooled firsts to first set of each A
  263. #                       goto loop2
  264. #
  265. #
  266. #               This algorithm is implemented by the following procedures:-
  267. #
  268. #                 get_firsts(Epsilon_Set) -- compute first sets of all
  269. #                    NTs, given the NTs that have epsilon productions.
  270. #
  271. #                 fill_firsts(needs) -- given the needs table that says
  272. #                    which first set contains the elements of other
  273. #                    first set(s), complete computation of first sets.
  274. #
  275. #                 buildgraph(tempL) -- given the productions in tempL,
  276. #                    build table G above.
  277. #
  278. #                 closure(G, S1, S2) -- given the productions in tempL,
  279. #                    the entry value S1 and its closure set S2, build 
  280. #                    closure_table.
  281. #
  282. #                 addnode(n, t) -- given table t ( G, actually), and
  283. #                    1. entry value of n, enter its assigned value in
  284. #                       in table t to be a set (empty, for now) 
  285. #                    2. use t[n] (in 1) as the entry value, enter its
  286. #                       assigned value in table t to be "n".
  287. #
  288. #                 closed_loop(G, SS, closure_table, tempL_i) -- given
  289. #                    table G, closure_table and a nonterminal tempL_i
  290. #                    that still needs its firsts completed, return the
  291. #                    set SS of nonterminals if each and every of these
  292. #                    nonterminals has identical closure set.
  293. #
  294. #                 finish_firsts(closed_set) -- given the set closed_set
  295. #                    of nonterminals where every member of of the set
  296. #                    has identical closure set, pool the elements 
  297. #                    (terminals) from their so-far known firsts sets
  298. #                    together and reenter this pooled value into their
  299. #                    firsts sets (firsts table).
  300. #
  301. #       2.2  Note that buildgraph(), closure() and addnode()
  302. #                 are either exactly or essentially the same as
  303. #                 given in class (by R. Griswold).
  304. #
  305. #**********************************************************************
  306.  
  307. procedure get_firsts(Epsilon_Set)
  308.   local needs, prods, i, j, k, token
  309.  
  310.   needs := table()
  311.   prods := sort(prod_table, 3)
  312.   every i := 1 to *prods by 2 do                # production(s) of a NT
  313.     every j := 1 to *prods[i+1] do              # RHS of each production
  314.       every k := 1 to *prods[i+1][j].rhs do     #  and each token
  315.         if ((token := prods[i+1][j].rhs[k]) == epsilon) then
  316.           break                                 # did in get_productions
  317.         else if member(Ts, token) then {        # leading token on RHS
  318.           insert(firsts[prods[i]], token)       # e.g. A -> ( B )
  319.           break
  320.         }
  321.         else { #if member(NTs, token) then      #      A -> B a C
  322.           /needs[prods[i]] := [] 
  323.           put(needs[prods[i]], token)
  324.           if not (member(Epsilon_Set, token)) then # not B -> EPSILON
  325.             break
  326.           if k = *prods[i+1][j].rhs then   # all RHS tokens are NTs &
  327.             insert(Epsilon_Set, prods[i])  # each has epsilon production
  328.         }
  329.   fill_firsts(needs)    # do firsts that contain firsts of other NT(s)
  330.   every insert(firsts[!Epsilon_Set], epsilon) # add epsilon last
  331. end
  332.  
  333. procedure fill_firsts(needs)
  334.   local G, L, NTy, SS, closed_set, closure_table, has_all_1st, i, lhs
  335.   local new_temp, rhs, size_has_all_1st, ss, ss_table, tempL, x
  336.  
  337.   closure_table := table()
  338.   has_all_1st := copy(NTs)              # set of NTs whose firsts fully defined
  339.   tempL := sort(needs, 3)
  340.   every i := 1 to *tempL by 2 do
  341.     delete(has_all_1st, tempL[i])
  342.   repeat {
  343.     ss := ""
  344.     ss_table := table()
  345.     size_has_all_1st := *has_all_1st
  346.     new_temp := list()
  347.     while lhs := pop(tempL) do {
  348.       rhs := pop(tempL)
  349.       L := list()
  350.       while NTy := pop(rhs) do
  351.         if NTy ~== lhs then
  352.           if member(has_all_1st, NTy) then
  353.             firsts[lhs] ++:= firsts[NTy]
  354.           else
  355.             put(L, NTy)
  356.       if *L = 0 then
  357.         insert(has_all_1st, lhs)
  358.       else {
  359.         put(new_temp, lhs)
  360.         put(new_temp, L)
  361.       }
  362.     }
  363.     tempL := new_temp
  364.     if *has_all_1st = *NTs then
  365.       break
  366.     if size_has_all_1st = *has_all_1st then {
  367.       G := buildgraph(tempL)
  368.       every i := 1 to *tempL by 2 do 
  369.         closure_table[tempL[i]] := closure(G, tempL[i])
  370.       every i := 1 to *tempL by 2 do {
  371.         closed_set := set()
  372.         SS := set([tempL[i]])
  373.         every x := !closure_table[tempL[i]] do
  374.           insert(SS, G[x])
  375.         closed_set := closed_loop(G,SS,closure_table,tempL[i])
  376.         if \closed_set then {
  377.           finish_firsts(closed_set) 
  378.           every insert(has_all_1st, !closed_set)
  379.           break
  380.         }
  381.       }
  382.     }
  383.   }
  384.   return
  385. end
  386.  
  387. procedure buildgraph(tempL)     # modified from the original version 
  388.   local arclist, nodetable, x, i
  389.  
  390.   arclist := []                 # by Ralph Griswold
  391.   nodetable := table()
  392.   every i := 1 to *tempL by 2 do {
  393.     every x := !tempL[i+1] do {
  394.      addnode(tempL[i], nodetable)
  395.      addnode(x, nodetable)
  396.      put(arclist, arc(tempL[i], x))
  397.     }
  398.   }
  399.   while x := get(arclist) do
  400.     insert(nodetable[x.From], nodetable[x.To])
  401.   return nodetable
  402. end
  403.  
  404. procedure closure(G, S1, S2)    # modified from the original version 
  405.   local S
  406.  
  407.   /S2 := set([G[S1]])           # by Ralph Griswold
  408.   every S := !(G[S1]) do
  409.     if not member(S2, S) then {
  410.       insert(S2, S)
  411.       closure(G, G[S], S2)
  412.     }
  413.   return S2
  414. end
  415.  
  416. procedure addnode(n, t)         # author: Ralph Griswold 
  417.   local S
  418.  
  419.   if /t[n] then {
  420.     S := set()
  421.     t[n] := S
  422.     t[S] := n
  423.   }
  424.   return
  425. end
  426.  
  427. procedure closed_loop(G, SS, closure_table, tempL_i)
  428.   local S, x, y
  429.  
  430.   delete(SS, tempL_i)
  431.   every x := !SS do {
  432.     S := set()
  433.     every y := !closure_table[x] do
  434.       insert(S, G[y])
  435.     delete(S, tempL_i)
  436.     if *S ~= *SS then fail
  437.     every y := !S do
  438.       if not member(SS, y) then fail
  439.   }
  440.   return insert(SS, tempL_i)
  441. end 
  442.  
  443. procedure finish_firsts(closed_set)
  444.   local S, x
  445.  
  446.   S := set()
  447.   every x := !closed_set do
  448.     every insert(S, !firsts[x]) 
  449.   every x := !closed_set do
  450.     every insert(firsts[x], !S)
  451. end
  452. #**********************************************************************
  453. #*                                                                    *
  454. #* Routines to generate states                                        *
  455. #**********************************************************************
  456. #
  457. #  1.  Data structures:-
  458. #
  459. #       E.g. Augmented grammar:-
  460. #       
  461. #               START -> S              (production 0)
  462. #               S -> ( S )              (production 1)
  463. #               S -> ( )                (production 2)
  464. #
  465. #             Item is a record of 5 fields:-
  466. #                 Example of an item: itemL[1] is [START->.S , $] 
  467. #                      prodN     represents the production number
  468. #                      lhs       represents the nonterminal at the
  469. #                                left hand side of the production
  470. #                      rhs1      represents the list of tokens seen so 
  471. #                                far (i.e. left of the dot in item)
  472. #                      rhs2      represents the list of tokens yet to be
  473. #                                seen (i.e. right of the dot in item)
  474. #                      NextI     represents the next input symbol
  475. #                                (the end of input symbol $ is 
  476. #                                represented by EOI.)
  477. #             
  478. #             
  479. #                  item             
  480. #                                _________       _________
  481. #                           prodN|   0   |       |   1   |
  482. #                                |-------|       |-------|
  483. #                           lhs  |"START"|       |  "S"  |
  484. #               _______          |-------|       |-------|     
  485. #       itemL   |  ---|-->[ rhs1 |    ---|---| , |  -----|---| , ...  ]
  486. #               -------          |-------|   |   |-------|   | 
  487. #                           rhs2 |    ---|-| |   |  -----|-| |
  488. #                                |-------| | |   |-------| | | 
  489. #                           NextI| "EOI" | | |   | "EOI" | | | 
  490. #                                --------- | |   --------- | | 
  491. #                                          | |             | | 
  492. #                                          | |             | |    
  493. #                                          | v             | v
  494. #                                          | []            | []
  495. #                                          |               |
  496. #                                          v               v
  497. #                                          ["S"]           ["(", "S", ")"]
  498. #
  499. #                 state
  500. #                                _______         
  501. #                           C_Set|  ---|-----|
  502. #               _______          |-----|     |
  503. #       stateL  |  ---|-->[ I_Set|  ---|---| |  , ...  ]
  504. #               -------          |-----|   | | 
  505. #                           goto |  ---|-| | |
  506. #                                ------- | | |
  507. #                                        | | v
  508. #                                        | | (1, 2, 3)
  509. #                                        | v        
  510. #                                        | (1)   
  511. #                                        v        
  512. #                                        __________________    
  513. #                                   | "A" |    5     |
  514. #                             |-----|----------|
  515. #                             | "B" |    2     |
  516. #                             |-----|----------|
  517. #                             | "C" |    3     |
  518. #                             ------------------
  519. #
  520. #
  521. #       (Note: 1.  The above 2 lists:-
  522. #                    -- are not to be popped
  523. #                    -- new elements are put in the back
  524. #                    -- index represents the identity of the element
  525. #                    -- no duplicate elements in either list
  526. #           2.  The state record:-
  527. #            I_Set represents J in function goto(I,x) in 
  528. #               Compiler, Aho, et al, Addison-Wesley, 1986,
  529. #              p. 232.
  530. #            C_Set represents the closure if I_Set.
  531. #            goto is part of the goto table and the shift 
  532. #              actions of the final parse table.)
  533. #              3.  The 1 in C_Set and I_Set in the diagrams above refer 
  534. #                       the same (physical) element.
  535. #
  536. #  2.  Algorithms:-
  537. #
  538. #         state0() -- create itemL[1] and stateL[1] as well as its
  539. #                       closure.
  540. #
  541. #         item_num(P_num, N_lhs, N_rhs1, N_rhs2, NI) --
  542. #                     if the item with the values given in the
  543. #                       argument list already exists in itemL list,
  544. #                       it returns the index of the item in the list,
  545. #                     if not, it builds a new item and put it at the 
  546. #                       end of the list and returns the new index.
  547. #
  548. #       prod_equal(prod1, prod2) --  prod1 and prod2 are lists of
  549. #              strings; fail if they are not the same.
  550. #
  551. #       state_closure(st) -- given the item set (I_set of the state 
  552. #              st), set the value of C_Set of st to the closure
  553. #              of this item set.  For definition of closure, 
  554. #                     see Aho, et al, Compilers..., Addison-Wesley, 
  555. #              1986, pp. 222-224)
  556. #              
  557. #       new_item(st,O_itm) -- given the state st and an item O_itm,
  558. #              suppose the item has the following configuration:-
  559. #                 [A -> B.CD,x]
  560. #              where CD is a string of terminal and nonterminal
  561. #              tokens.  If C is a nonterminal, 
  562. #                 for each C -> E in the grammar, and 
  563. #            for each y in first(Dx), add the new item
  564. #                 [C -> .E,y] 
  565. #            to the C_Set of st.
  566. #
  567. #       all_firsts(itm) -- given an item itm and suupose it has the
  568. #              following configuration:-
  569. #                 [A -> B.CD,x]
  570. #              where D is a string of terminal and nonterminal
  571. #              tokens.  The procedure returns first(Dx).
  572. #
  573. #       gotos() -- For definition of goto operation, see Aho, et al,
  574. #                    Compilers..., Addison-Wesley, 1986, pp. 224-227)
  575. #             The C = {closure({[S'->S]})} is set up by the
  576. #                    state0()
  577. #             call in the main procedure.
  578. #    
  579. #             It also compiles the goto table.  The errata part
  580. #             (last section of the code in this procedure) is
  581. #             for debugging purposes and is left intact for now.
  582. #              
  583. #       moved_item(itm) -- given the item itm and suppose it has the
  584. #              following configuration:-
  585. #                 [A -> B.CD,x]
  586. #              where D is a string of terminal and nonterminal
  587. #              tokens.  The procedure builds a new item:-
  588. #                 [A -> BC.D,x]
  589. #              It then looks up itemL to see if it already is
  590. #              in it.  If so, it'll return its index in the list,
  591. #              else, it'll put it in the back of the list and
  592. #              return this new index.  (This is done by calling
  593. #              item_num()).
  594. #              
  595. #       exists_I_Set(test) -- given the I_Set test, look in the stateL
  596. #             list and see if any state does contain similar
  597. #             I_Set, if so, return its index to the stateL list,
  598. #             else fail.
  599. #              
  600. #      set_equal(set1, set2) -- set1 and set2 are sets of integers;
  601. #              return set1 if the two sets have the same elements
  602. #              else fail.  (It is used strictly in comparison of
  603. #              I_Sets).
  604. #
  605. #
  606. #**********************************************************************
  607.  
  608. procedure state0()
  609.   local itm, st
  610.  
  611.   itm := item_num(0, start, [], [StartSymbol], eoi)
  612.   st := state(set(), set([itm]), table())
  613.   put(stateL, st)
  614.   state_closure(st)     # closure on initial state
  615. end
  616.  
  617. procedure item_num(P_num, N_lhs, N_rhs1, N_rhs2, NI)
  618.   local itm, i
  619.  
  620.   itm := item(P_num, N_lhs, N_rhs1, N_rhs2, NI)
  621.   every i := 1 to *itemL do {
  622.     if itm.prodN ~== itemL[i].prodN then next
  623.     if itm.lhs ~== itemL[i].lhs then next
  624.     if not prod_equal(itm.rhs1, itemL[i].rhs1) then next
  625.     if not prod_equal(itm.rhs2, itemL[i].rhs2) then next
  626.     if itm.NextI == itemL[i].NextI then return i
  627.   }
  628.   put(itemL, itm)
  629.   return *itemL
  630. end
  631.  
  632. procedure prod_equal(prod1, prod2)      # compare 2 lists of strings
  633.   local i
  634.  
  635.   if *prod1 ~= *prod2 then fail
  636.   every i := 1 to *prod1 do
  637.     if prod1[i] ~== prod2[i] then fail
  638.   return
  639. end
  640.  
  641. procedure state_closure(st)
  642.   local addset, more_set, i
  643.  
  644.   st.C_Set := copy(st.I_Set)
  645.   addset := copy(st.C_Set)
  646.   while *addset > 0 do {
  647.     more_set := set()
  648.     every i := !addset do
  649.       if (itemL[i].rhs2[1] ~== epsilon) then
  650.         if member(NTs, itemL[i].rhs2[1]) then
  651.           more_set ++:= new_item(st,itemL[i])
  652.     addset := more_set
  653.   }
  654. end
  655.  
  656. procedure new_item(st,O_itm)
  657.   local N_Lhs, N_Rhs1, N_prod, NxtInput, T_itm, i, rtn_set
  658.   rtn_set := set()
  659.   NxtInput := all_firsts(O_itm)
  660.   N_Lhs := O_itm.rhs2[1]
  661.   N_Rhs1 := []
  662.   every N_prod := !prod_table[N_Lhs] do
  663.     every i := !NxtInput do {
  664.       T_itm := item_num(N_prod.num, N_Lhs, N_Rhs1, N_prod.rhs, i)
  665.       if not member(st.C_Set, T_itm) then {
  666.         insert(st.C_Set, T_itm)
  667.         insert(rtn_set, T_itm)
  668.       }
  669.     }
  670.   return rtn_set
  671. end
  672.  
  673. procedure all_firsts(itm)
  674.   local rtn_set, i
  675.  
  676.   if *itm.rhs2 = 1 then
  677.     return set([itm.NextI])
  678.   rtn_set := set()
  679.   every i := 2 to *itm.rhs2 do
  680.     if member(Ts, itm.rhs2[i]) then 
  681.       return insert(rtn_set, itm.rhs2[i])
  682.     else {
  683.       rtn_set ++:= firsts[itm.rhs2[i]]
  684.       if not member(firsts[itm.rhs2[i]], epsilon) then
  685.         return rtn_set
  686.     }
  687.   return insert(rtn_set, itm.NextI)
  688. end
  689.  
  690. procedure gotos()
  691.   local New_I_Set, gost, i, i_num, j, j_num, looked_at, scan, st, st_num, x
  692.   st_num := 1
  693.   repeat{
  694.     looked_at := set()
  695.     scan := sort(stateL[st_num].C_Set)
  696.     every i := 1 to *scan do {
  697.       i_num := scan[i]
  698.       if member(looked_at, i_num) then next
  699.       insert(looked_at, i_num)
  700.       x := itemL[i_num].rhs2[1]         # next LHS
  701.       if ((*itemL[i_num].rhs2 = 0) | (x == epsilon)) then next
  702.       New_I_Set := set([moved_item(itemL[i_num])])
  703.       every j := i+1 to *scan do {
  704.         j_num := scan[j]
  705.         if not member(looked_at, j_num) then
  706.           if (x == itemL[j_num].rhs2[1]) then {
  707.             insert(New_I_Set, moved_item(itemL[j_num]))
  708.             insert(looked_at, j_num)
  709.           }
  710.       }
  711.       if gost := exists_I_Set(New_I_Set) then 
  712.         stateL[st_num].goto[x] := gost    #add into goto
  713.       else { # add a new state
  714.         st := state(set(), New_I_Set, table())
  715.         put(stateL, st)
  716.         state_closure(st)
  717.         stateL[st_num].goto[x] := *stateL    #add into goto
  718.       }
  719.     }
  720.     if erratta=1 then {
  721.       write("--------------------------------")
  722.       write("State ", st_num-1)
  723.       write_state(stateL[st_num])
  724.     }
  725.     st_num +:= 1
  726.     if st_num > *stateL then {
  727.       if erratta=1 then
  728.         write("--------------------------------")
  729.       return stateL
  730.     }
  731.   }
  732. end
  733.  
  734. procedure moved_item(itm)
  735.   local N_Rhs1, N_Rhs2, i
  736.  
  737.   N_Rhs1 := copy(itm.rhs1)
  738.   put(N_Rhs1, itm.rhs2[1])
  739.   N_Rhs2 := list()
  740.   every i := 2 to *itm.rhs2 do
  741.     put(N_Rhs2, itm.rhs2[i])
  742.   return item_num(itm.prodN, itm.lhs, N_Rhs1, N_Rhs2, itm.NextI)
  743. end
  744.  
  745. procedure exists_I_Set(test)
  746.   local st
  747.  
  748.   every st := 1 to *stateL do
  749.     if set_equal(test, stateL[st].I_Set) then return st
  750.   fail
  751. end
  752.  
  753. procedure set_equal(set1, set2)         
  754.   local i
  755.  
  756.    if *set1 ~= *set2 then fail
  757.    every i := !set2 do
  758.      if not member(set1, i) then fail
  759.    return set1
  760. end
  761. #**********************************************************************
  762. #*                                                                    *
  763. #* Miscellaneous write routines                                       *
  764. #**********************************************************************
  765. #    The following are write routines; some for optional output
  766. #    while others are for debugging purposes. 
  767. #        write_item(itm) -- write the contents if item itm.
  768. #        write_state(st) -- write the contents of state st.
  769. #        write_tbl_list(out) -- (for debugging purposes only).
  770. #        write_prods()-- write the enmnerated grammar productions.
  771. #        write_NTs() -- write the set of nonterminals.
  772. #        write_Ts() -- write the set of terminals.
  773. #        write_firsts() -- write the first sets of each nonterminal.
  774. #        write_needs(L) -- write the list of all nonterminals and the
  775. #                  associated nonterminals whose first sets 
  776. #                  it still needs to compute its own first
  777. #                  set.
  778. #**********************************************************************
  779.  
  780. procedure write_item(itm)
  781.   local i
  782.  
  783.   writes("[(",itm.prodN,") ",itm.lhs," ->")
  784.   every i := !itm.rhs1 do writes(" ",i)
  785.   writes(" .")
  786.   every i := !itm.rhs2 do writes(" ",i)
  787.   writes(", ",itm.NextI,"]\n")
  788. end
  789.  
  790. procedure write_state(st)
  791.   local i, tgoto
  792.  
  793.   write("I_Set")
  794.   every i := ! st.I_Set do {
  795.     writes("Item ", i, " ")
  796.     write_item(itemL[i])
  797.   }
  798.   write()
  799.   write("C_Set")
  800.   every i := ! st.C_Set do {
  801.     writes("Item ", i, " ")
  802.     write_item(itemL[i])
  803.   }
  804.   tgoto := sort(st.goto, 3)
  805.   write()
  806.   write("Gotos")
  807.   every i := 1 to *tgoto by 2 do
  808.     write("Goto state ", tgoto[i+1]-1, " on ", tgoto[i])
  809. end
  810.  
  811. procedure write_tbl_list(out)
  812.   local i, j
  813.  
  814.   every i := 1 to *out by 2 do {
  815.     writes(out[i], ", [")
  816.     every j := *out[i+1] do {
  817.       if j ~= 1 then
  818.         writes(", ")
  819.       writes(out[i+1][j])
  820.     }
  821.     writes("]\n")
  822.   }
  823. end
  824.  
  825. procedure write_prods()
  826.   local i, j, k, prods
  827.  
  828.   prods := sort(prod_table, 3)
  829.   every i := 1 to *prods by 2 do 
  830.     every j := 1 to *prods[i+1] do {
  831.       writes(right(string(prods[i+1][j].num),3," "),":  ")
  832.       writes(prods[i], " ->")
  833.       every k := 1 to *prods[i+1][j].rhs do
  834.         writes(" ", prods[i+1][j].rhs[k])
  835.       writes("\n")
  836.     }
  837. end
  838.  
  839. procedure write_NTs()
  840.   local temp_list
  841.  
  842.   temp_list := sort(NTs)
  843.   write("\n")
  844.   write("nonterminal sets are:")
  845.   every write(|pop(temp_list))
  846. end
  847.  
  848. procedure write_Ts()
  849.   local temp_list
  850.  
  851.   temp_list := sort(Ts)
  852.   write("\n")
  853.   write("terminal sets are:")
  854.   every write(|pop(temp_list))
  855. end
  856.  
  857. procedure write_firsts()
  858.   local temp_list, i, j, first_list
  859.  
  860.   temp_list := sort(firsts, 3)
  861.   write("\nfirst sets:::::")
  862.   every i := 1 to *temp_list by 2 do {
  863.     writes(temp_list[i], ": ")
  864.     first_list := sort(temp_list[i+1])
  865.     every j := 1 to *first_list do
  866.       writes(" ", pop(first_list))
  867.     writes("\n\n")
  868.   }
  869. end
  870.  
  871. procedure write_needs(L)
  872.   local i, temp
  873.  
  874.   write("tempL : ")
  875.   every i := 1 to *L by 2 do {
  876.     writes(L[i], " ")
  877.     temp := copy(L[i+1])
  878.     every writes(|pop(temp))
  879.     writes("\n")
  880.   }
  881. end
  882. #**********************************************************************
  883. #*                                                                    *
  884. #* Output the parse table routines                                    *
  885. #**********************************************************************
  886. #
  887. #    p_table() -- output parse table: tablulated (vertical and
  888. #             horizontal lines, etc.) if the width is within
  889. #             80 characters long else a listing.
  890. #
  891. #    outline(size, out, st_num, T_list, NT_list) -- print the header;
  892. #             used in table form.
  893. #
  894. #    border(size, T_list, NT_list, col) -- draw a horizontal line
  895. #             for the table form, given the table size that tells
  896. #             the length of each token given the lists of 
  897. #             terminals and nonterminals.  If the line is the 
  898. #             last line of the table, col given is "-", else it 
  899. #             is "-". 
  900. #
  901. #    outstate(st, out, T_list, NT_list) -- print the shift, reduce
  902. #             and goto for state st from information given in
  903. #             out, and the lists of terminals and nonterminals;
  904. #             used to output the parse table in the listing form.
  905. #
  906. #**********************************************************************
  907.  
  908. procedure p_table()
  909.   local NT_list, T_list, action, gs, i, itm, msize, out, s, size, st_num, tsize
  910.  
  911.   T_list := sort(Ts)
  912.   put(T_list, eoi)
  913.   NT_list := sort(NTs)
  914.   size := table()
  915.   out := table()
  916.   if *stateL < 1000 then msize := 4
  917.   else if *stateL < 10000 then msize := 5
  918.   else msize := 6
  919.   tsize := 7
  920.   every s := !T_list do {
  921.     size[s] := *s
  922.     size[s] <:= msize
  923.     tsize +:= size[s] + 3
  924.     out[s] := s
  925.   }
  926.   every s := !NT_list do {
  927.     size[s] := *s
  928.     size[s] <:= msize
  929.     tsize +:= size[s] + 3
  930.     out[s] := s
  931.   }
  932.   write()
  933.   write()
  934.   write("PARSE TABLE")
  935.   write()
  936.   if tsize <= 80 then {
  937.     outline(size, out, 0, T_list, NT_list)
  938.     border(size, T_list, NT_list, "+")
  939.   }
  940.   every st_num := 1 to *stateL do {
  941.     out := table()
  942.     gs := sort(stateL[st_num].goto,3)
  943.     every i := 1 to * gs by 2 do {  # do the shifts and gotos
  944.       if member(Ts, gs[i]) then
  945.         out[gs[i]] := "S" || string(gs[i+1]-1)    # shift (action table)
  946.       else
  947.         out[gs[i]] := string(gs[i+1]-1)        # for goto table
  948.     }
  949.     every itm := itemL[!stateL[st_num].C_Set] do {
  950.       if ((*itm.rhs2 = 0) | (itm.rhs2[1] == epsilon))  then {
  951.         if itm.prodN = 0 then
  952.           action := "ACC"            # accept state
  953.         else
  954.           action := "R" || string(itm.prodN)    # reduce (action table)
  955.         if /out[itm.NextI] then
  956.           out[itm.NextI] := action
  957.         else { # conflict
  958.           write(&errout, "Conflict on state ", st_num-1, " symbol ",
  959.            itm.NextI, " between ", action, " and ", out[itm.NextI])
  960.           write(&errout, "  ", out[itm.NextI], " takes presidence")
  961.         }
  962.       }
  963.     }
  964.     if tsize <= 80 then
  965.       outline(size, out, st_num, T_list, NT_list)
  966.     else
  967.       outstate(st_num, out, T_list, NT_list)
  968.   }
  969. end
  970.  
  971. procedure outline(size, out, st_num, T_list, NT_list)
  972.   local s
  973.  
  974.   if st_num = 0 then
  975.     writes("State")
  976.   else
  977.     writes(right(string(st_num-1),5," "))
  978.   writes(" ||")
  979.   every s := !T_list do {
  980.     /out[s] := ""
  981.     writes(" ", center(out[s],size[s]," "), " |")
  982.   }
  983.   writes("|")
  984.   every s := !NT_list do {
  985.     /out[s] := ""
  986.     writes(" ", center(out[s],size[s]," "), " |")
  987.   }
  988.   write()
  989.   if st_num < * stateL then
  990.     border(size, T_list, NT_list, "+")
  991.   else
  992.     border(size, T_list, NT_list, "-")
  993. end
  994.  
  995. procedure border(size, T_list, NT_list, col)
  996.   local s
  997.  
  998.   writes("------", col, col)
  999.   every s := !T_list do
  1000.     writes("-", center("",size[s],"-"),"-", col)
  1001.   writes(col)
  1002.   every s := !NT_list do
  1003.     writes("-",center("",size[s],"-"), "-", col)
  1004.   writes("\n")
  1005. end
  1006.  
  1007. procedure outstate(st, out, T_list, NT_list)
  1008.   local s
  1009.  
  1010.   write()
  1011.   write("Actions for state ", st-1)
  1012.   every s := !T_list do
  1013.     if \out[s] then
  1014.       if out[s][1] == "R" then
  1015.         write("   On ", s, " reduce by production ", out[s][2:0])
  1016.       else if out[s][1] == "A" then
  1017.     write("   On ", s, " ACCEPT")
  1018.       else
  1019.         write("   On ", s, " shift to state ", out[s][2:0])
  1020.   every s := !NT_list do
  1021.     if \out[s] then
  1022.       write("   On ", s, " Goto ", out[s])
  1023.   write()
  1024. end
  1025.  
  1026.